import sys
import logging
import sqlalchemy
from lxml import etree
from xadmin.model import *
from xadmin.lib.base import *

log = logging.getLogger(__name__)

class TestcasesController(BaseController):
    """REST Controller styled on the Atom Publishing Protocol"""
    # To properly map this controller, ensure your config/routing.py file has
    # a resource setup:
    #     map.resource('testcase', 'testcases')


    def index(self, format='html'):
        """GET /testcases: All items in the collection."""
        # url_for('testcases')
        c.test_cases = Session.query(TestCase).all()
        response.headers['Content-Type'] = 'text/xml; charset=utf-8'
        return render('/testcases/list.mako')

    def listByProject(self, project):
        """GET /:project/testcases: All items in the project."""
        # url_for('testcases_by_project')
        project = Session.query(Project).get(project)
        if project is not None:
            c.test_cases = project.test_cases
            response.headers['Content-Type'] = 'text/xml; charset=utf-8'
            return render('/testcases/list.mako')
        else:
            abort(404)

    def listByRequirement(self, project, requirement):
        """GET /:project/:requirement/acceptancetests: All items in the project."""
        # url_for('acceptancetests_by_requirement')
        project = Session.query(Project).get(project)
        if project is not None:
            requirement = Session.query(ProductRequirement).get(requirement)
            if requirement is not None:
                c.test_cases = requirement.test_cases
                response.headers['Content-Type'] = 'text/xml; charset=utf-8'
                return render('/testcases/list.mako')
            else:
                abort(404)
        else:
            abort(404)

    def create(self):
        """POST /testcases: Create a new item."""
        # url_for('testcases')
        try:
            content = request.body.read(int(request.environ['CONTENT_LENGTH']))
            if not content:
                content = request.params.get('xml')
            tc = self._createTestCase(None, content)
            del response.headers['Content-Type']
            response.headers['Location'] = '/testcases/%s' % tc.id
            response.status_code = 201
            return
        except:
            print "ERROR: ", sys.exc_info()[0]
            abort(400)

    def createByProject(self, project):
        """POST /:project/testcases: Create a new Test Case to a project."""
        # url_for('create_testcases_by_project')
        project = Session.query(Project).get(project)
        if project is not None:
            content = request.body.read(int(request.environ['CONTENT_LENGTH']))
            if not content:
                content = request.params.get('xml')
            tc = self._createTestCase(project.id, content)
            del response.headers['Content-Type']
            response.headers['Location'] = '/testcases/%s' % tc.id
            response.status_code = 201
            return
        else:
            abort(404)

    def createByRequirement(self, project, requirement):
        """POST /:project/acceptancetests: Create a new Test Case to a project."""
        # url_for('create_testcase_by_requirement')
        project = Session.query(Project).get(project)
        if project is not None:
            pr = Session.query(ProductRequirement).get(requirement)
            if requirement is not None:
                content = request.body.read(int(request.environ['CONTENT_LENGTH']))
                if not content:
                    content = request.params.get('xml')
                tc = self._createTestCase(project.id, content, pr.id)
                del response.headers['Content-Type']
                response.headers['Location'] = self._getAbsoluteURL(h.url_for('testcase', id=tc.id))
                response.status_code = 201
                return
            else:
                abort(404)
        else:
            abort(404)

    def new(self, format='html'):
        """GET /testcases/new: Form to create a new item."""
        # url_for('new_testcase')
        c.url = h.url_for('new_testcase')
        response.headers['Content-Type'] = 'text/xml; charset=utf-8'
        return render('/testcases/form.mako')

    def newByProject(self, project):
        """GET /:project/testcases/new: Form to create a new item for a project."""
        # url_for('new_testcase_by_project')
        c.project = project
        c.url = h.url_for('create_testcases_by_project', project=project)
        response.headers['Content-Type'] = 'text/xml; charset=utf-8'
        return render('/testcases/form.mako')

    def newByRequirement(self, project, requirement):
        """GET /testcases/new: Form to create a new item associated to a requirement."""
        # url_for('new_testcase_by_requirement')
        try:
            c.url = h.url_for('create_testcase_by_requirement', project=project, requirement=requirement)
            c.requirement = requirement
            response.headers['Content-Type'] = 'text/xml; charset=utf-8'
            return render('/testcases/form.mako')
        except:
            abort(404)

    def update(self, id):
        """PUT /testcases/id: Update an existing item."""
        # Forms posted to this method should contain a hidden field:
        #    <input type="hidden" name="_method" value="PUT" />
        # Or using helpers:
        #    h.form(h.url_for('testcase', id=ID),
        #           method='put')
        # url_for('testcase', id=ID)
        tc = Session.query(TestCase).get(id)
        if tc:
            try:
                content = request.body.read(int(request.environ['CONTENT_LENGTH']))
                tree = etree.fromstring(content)
                name = tree.xpath('/test/name')
                if name:
                    tc.name = name[0].text
                description = tree.xpath('/test/description')
                if description:
                    tc.description = description[0].text
                input = tree.xpath('/test/input')
                if input:
                    tc.input = input[0].text
                output = tree.xpath('/test/output')
                if output:
                    tc.output = output[0].text
                #Session.save(tc)
                Session.commit()
                response.headers['Content-Type'] = 'text/xml; charset=utf-8'
                response.headers['Location'] = '/testcases/%s' % tc.id
                return
            except:
                abort(400)
        else:
            abort(404)

    def delete(self, id):
        """DELETE /testcases/id: Delete an existing item."""
        # Forms posted to this method should contain a hidden field:
        #    <input type="hidden" name="_method" value="DELETE" />
        # Or using helpers:
        #    h.form(h.url_for('testcase', id=ID),
        #           method='delete')
        # url_for('testcase', id=ID)
        tc = Session.query(TestCase).get(id)
        if tc:
            Session.delete(tc)
            Session.commit()
        del response.headers['Content-Type']
        response.status_code = 204

    def show(self, id, format='html'):
        """GET /testcases/id: Show a specific item."""
        # url_for('testcase', id=ID)
        c.case = Session.query(TestCase).get(id)
        if c.case:
            response.headers['Content-Type'] = 'text/xml; charset=utf-8'
            return render('/testcases/view.mako')
        else:
            abort(404)

    def edit(self, id, format='html'):
        """GET /testcases/id;edit: Form to edit an existing item."""
        # url_for('edit_testcase', id=ID)
        pass

    def _createTestCase(self, project_id, content, requirement=None):
        try:
            tree = etree.fromstring(content.encode("utf8"))
            if requirement is None:
                requirement = tree.xpath('/test/requirement')
                requirement = requirement[0].text
            name = tree.xpath('/test/name')[0].text
            description = tree.xpath('/test/description')[0].text
            setup = tree.xpath('/test/setup')[0].text
            input = tree.xpath('/test/input')[0].text
            output = tree.xpath('/test/output')[0].text
            tc = TestCase(name, description, input, output)
            tc.setup = setup
            if requirement:
                pr = Session.query(ProductRequirement).get(requirement)
                pr.test_cases.append(tc)
                pr.project.test_cases.append(tc)
            elif project_id is not None:
                project = Session.query(Project).get(project_id)
                project.test_cases.append(tc)
            Session.save(tc)
            Session.commit()
            return tc
        except:
            abort(400)
